﻿#pragma once

#include <functional>
#include <learn/dll_ext.h>
#include <learn/geom/vec.h>
#include <learn/utils/tga_image.h>

namespace xi
{

namespace painter
{

using namespace xi::geom;

class EXT_SYMBOL Painter2D
{
  public:
    /**
     * @brief 创建画框
     *
     * @param[in] width
     * @param[in] height
     */
    Painter2D(int width, int height);

    /**
     * @brief 获得程序运行时间
     *
     * @return long long
     */
    long long duration() const;

    /**
     * @brief 刷新窗口
     *
     */
    void refresh();

    /**
     * @brief 修改画框大小
     *
     * @param[in] width
     * @param[in] height
     */
    void resize(int width, int height);

    /**
     * @brief 获得图像
     *
     * @return TGA_Image
     */
    TGA_Image frame();

    /**
     * @brief 设置图像
     *
     * @param[in] frame
     */
    void set_frame(TGA_Image frame);

    /**
     * @brief 绘制单点
     *
     * @param[in] x
     * @param[in] y
     * @param[in] color
     * @param[in] size
     */
    void draw_point(int x, int y, TGA_Color color, int size = 1);

    /**
     * @brief Bersenham 法绘制直线
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] x1
     * @param[in] y1
     * @param[in] color
     */
    void draw_line(int x0, int y0, int x1, int y1, TGA_Color color);

    /**
     * @brief 吴晓林反走样画线 https://www.geeksforgeeks.org/anti-aliased-line-xiaolin-wus-algorithm/
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] x1
     * @param[in] y1
     * @param[in] color
     * @param[in] width
     */
    void draw_line_antialias(int x0, int y0, int x1, int y1, TGA_Color color, int width = 1);

    /**
     * @brief 绘制三角形
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] x1
     * @param[in] y1
     * @param[in] x2
     * @param[in] y2
     * @param[in] color
     * @param[in] width
     */
    void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, TGA_Color color, int width = 1);

    /**
     * @brief 绘制矩形
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] width
     * @param[in] height
     * @param[in] color
     */
    void draw_rectangle(int x0, int y0, int width, int height, TGA_Color color);

    /**
     * @brief 绘制折线段
     *
     * @param[in] points
     * @param[in] color
     * @param[in] width
     */
    void draw_polyline(const std::vector<Vec2i> &points, TGA_Color color, int width = 1);

    /**
     * @brief 绘制多边形
     *
     * @param[in] points
     * @param[in] color
     * @param[in] width
     */
    void draw_polygon(const std::vector<Vec2i> &points, TGA_Color color, int width = 1);

    /**
     * @brief Bresenham 画圆法
     *
     * @param[in] x
     * @param[in] y
     * @param[in] r
     * @param[in] color
     */
    void draw_circle(int x, int y, int r, TGA_Color color);

    /**
     * @brief 逐点比较法画圆
     *
     * @param[in] x
     * @param[in] y
     * @param[in] r
     * @param[in] color
     */
    void draw_circle_pointwise(int x, int y, int r, TGA_Color color);

    /**
     * @brief 简化的 Bresenham 画圆法 https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/
     *
     * @param[in] x
     * @param[in] y
     * @param[in] r
     * @param[in] color
     */
    void draw_circle_bresenham(int x, int y, int r, TGA_Color color);

    /**
     * @brief 中点椭圆法
     *
     * @param[in] x
     * @param[in] y
     * @param[in] width
     * @param[in] height
     * @param[in] color
     */
    void draw_ellispe(int x, int y, int width, int height, TGA_Color color);

    /**
     * @brief 绘制离散函数图像
     *
     * @param[in] f
     * @param[in] x0
     * @param[in] x1
     * @param[in] N
     * @param[in] color
     * @param[in] width
     */
    void draw_function(std::function<double(double)> f, int x0, int x1, int N, TGA_Color color, int width = 1);

    /**
     * @brief 填充三角形
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] x1
     * @param[in] y1
     * @param[in] x2
     * @param[in] y2
     * @param[in] color
     */
    void fill_triangle(int x0, int y0, int x1, int y1, int x2, int y2, TGA_Color color);

    /**
     * @brief 填充矩形
     *
     * @param[in] x0
     * @param[in] y0
     * @param[in] width
     * @param[in] height
     * @param[in] color
     */
    void fill_rectangle(int x0, int y0, int width, int height, TGA_Color color);

    /**
     * @brief 4 连通边界标记填充法
     *
     * @param[in] x
     * @param[in] y
     * @param[in] fillColor
     * @param[in] boundaryColor
     */
    void fill_boundary_4(int x, int y, TGA_Color fillColor, TGA_Color boundaryColor);

    /**
     * @brief 洪水填充法，填充同色像素
     * https://www.geeksforgeeks.org/flood-fill-algorithm-implement-fill-pastd::size_t/
     *
     * @param[in] x
     * @param[in] y
     * @param[in] fillColor
     * @param[in] sameColor
     */
    void fill_flood_4(int x, int y, TGA_Color fillColor, TGA_Color sameColor);

    /**
     * @brief 在指定位置绘制图像
     *
     * @param[in] x
     * @param[in] y
     * @param[in] filename
     */
    void draw_tga_image(int x, int y, const char *filename);

  protected:
    TGA_Image m_frame;
};

} // namespace painter

} // namespace xi
